/**
 * @file app_main.c
 * @brief 
 * @author WebbSu (sumg@bjbtech.com.cn)
 * @version 1.0
 * @date 2023-11-10
 * 
 * @copyright Copyright (c) 2023  必捷必（吉林省）有限公司
 * 
 * @par 修改日志:
 * fix  : 
 * feat : 
 */

#define LOG_TAG "main.tag"

#include "app_main.h"
#include "elog.h"

#include "bms_can.h"
#include "j1939tp.h"

#include <stdio.h>
#include <string.h>

#include "relay_ctrl.h"
#include "ele_lock_ctrl.h"
#include "emergency_ctrl.h"
#include "cc1_det.h"
#include "ins_det.h"
#include "temp_det.h"
#include "pe_det.h"

#include "cmd_map_rw.h"
#include "bms_mem_tab.h"
#include "pwr_mem_tab.h"
#include "charge_mem_tab.h"

#include "utils.h"
#include "../core/list.h"

static app_t app;
SemaphoreHandle_t sync_sem;
static void apptask_init(app_t *init);

/**
 * @brief RTOS任务参数
 */
osThreadId_t appTaskHandle;
const osThreadAttr_t appTask_attributes = {
    .name = "appTask",
    .stack_size = 2048 + 512,
    .priority = (osPriority_t)osPriorityRealtime7,
};

/**
 * @brief 创建任务同步的二值信号量
 */
int create_sync_semphr(void)
{
    int ret = 0;
    sync_sem = xSemaphoreCreateBinary();
    configASSERT(sync_sem);
    return ret;
}
INIT_APP_EXPORT(create_sync_semphr);

/**
 * @brief                   充电辨识状态实现
 * @param  identify         bms通讯结构
 * @return int              FSM_RUN：状态机运行  FSM_SUCCESS: 状态机完成  FSM_FAIL: 状态机出错
 */
static int identify_fsm(bms_t *const identify)
{
    int ret = FSM_RUN;
    static int retry = 0;
    cem_msg_t cem_msg = {0};

    switch (identify->iden_fsm.status)
    {
    case IDENTIFY_IDLE_STATE:
        log_d("identify idle.\r\n");
        clear_timer(&identify->timer[0]);
        set_timer(&identify->timer[0], 0, 5000);
        identify->iden_fsm.status = IDENTIFY_START_STATE;
        break;
    case IDENTIFY_START_STATE:
        RUN_PERIODIC_TASK(charge_send_crm(0x00), CRM_MESSAGE_PER);
        if (xTaskCheckTickTimeout(identify->timer[0].end_tick))
        {
            retry++;
            if (retry >= 3)
            {
                retry = 0;
                general_cmd_map_get(CMD_MAP_CHARGE, CHARGE_ERR_CODE, cem_msg.buf, 4u);
                cem_msg.data.byte0.brm_timeout = pdTRUE;
                general_cmd_map_set(CMD_MAP_CHARGE, CHARGE_ERR_CODE, cem_msg.buf, 4u);
                ret = FSM_FAIL;
                log_e("recv BRM message1 timeout 5S.");
                clear_timer(&identify->timer[0]);
                identify->iden_fsm.status = IDENTIFY_END_STATE;
            }
            else
            {
                clear_timer(&identify->timer[0]);
                set_timer(&identify->timer[0], 0, 5000);
            }
        }
        else if (identify->msg->j1939_bms.addr.pgn == BMS_BRM_PGN)
        {
            brm_msg_t brm_msg = {0};
            char vin[17 + 1] = {0};
            undata32_t undata32 = {0};

            retry = 0;
            log_d("recv BRM message success");
            clear_timer(&identify->timer[0]);
            set_timer(&identify->timer[0], 0, 5000);
            memcpy(brm_msg.buf, identify->msg->data.buf, sizeof(brm_msg.buf));
            memcpy(vin, brm_msg.data.vin, sizeof(brm_msg.data.vin));
            log_w("vin %s", vin);
            general_cmd_map_set(CMD_MAP_BMS, BMS_VIN_CODE, (uint8_t *)vin, sizeof(vin));
            log_w("bms version %d.%d.%d", brm_msg.data.pro_ver[2], brm_msg.data.pro_ver[1], brm_msg.data.pro_ver[0]);
            memcpy(undata32.data8, brm_msg.data.pro_ver, 3u);
            if (undata32.data32 == CHARGE_CAN_VERSION)
            {
                identify->iden_fsm.status = IDENTIFY_ACK_STATE;
            }
            else
            {
                ret = FSM_FAIL;
                identify->iden_fsm.status = IDENTIFY_END_STATE;
            }
        }
        break;
    case IDENTIFY_ACK_STATE: /* SPN2560 = 0xAA */
        RUN_PERIODIC_TASK(charge_send_crm(0xAA), CRM_MESSAGE_PER);
        if (xTaskCheckTickTimeout(identify->timer[0].end_tick))
        {
            retry++;
            if (retry >= 3)
            {
                retry = 0;
                ret = FSM_FAIL;
                log_e("recv BRM message2 timeout 5S.");
                clear_timer(&identify->timer[0]);
                identify->iden_fsm.status = IDENTIFY_END_STATE;
            }
            else
            {
                clear_timer(&identify->timer[0]);
                set_timer(&identify->timer[0], 0, 5000);
            }
        }
        else if (identify->msg->j1939_bms.addr.pgn == BMS_BCP_PGN)
        {
            bcp_msg_t bscp = {0};
            uint16_t soc = 0;
            
            retry = 0;
            memcpy(bscp.buf, identify->msg->data.buf, identify->msg->data.len);
            log_w("soc %d", bscp.data.vehicle_soc);
            log_w("batt vol %d", bscp.data.batt_vol);
            log_w("max batt vol %d", bscp.data.max_charge_vol);             /* 精度0.1 */
            soc = (uint16_t)(bscp.data.vehicle_soc / 10);
            general_cmd_map_set(CMD_MAP_CHARGE, CHARGE_SOC, (uint8_t *)&soc, 2u);
            general_cmd_map_set(CMD_MAP_BMS, BMS_CURR_VOL, (uint8_t *)&bscp.data.batt_vol, 2u);
            if ((bscp.data.max_charge_vol <= PWR_MAX_OUT_VOL && bscp.data.max_charge_curr <= PWR_MAX_OUT_CURR) || \
                (bscp.data.batt_vol <= (1000 * 10) && bscp.data.batt_vol >= (200 * 10)))
            {
                ret = FSM_SUCCESS;
                identify->iden_fsm.status = IDENTIFY_IDLE_STATE;
                clear_timer(&identify->timer[0]);
            }
            else
            {
                ret = FSM_FAIL;
                identify->iden_fsm.status = IDENTIFY_END_STATE;
            }
        }
        break;
    case IDENTIFY_END_STATE:
        identify->iden_fsm.status = IDENTIFY_IDLE_STATE;
        break;
    default:
        break;
    }
    return ret;
}

/**
 * @brief                   充电参数配置阶段状态机
 * @param  config           充电参数配置操作对象
 * @param  msg              充电功率模块数据
 * @return int              FSM_RUN：状态机运行  FSM_SUCCESS: 状态机完成  FSM_FAIL: 状态机出错
 */
int config_fsm(bms_t *const config, pwr_msg_t const *const msg)
{
    int ret = FSM_RUN;
    static int retry = 0;
    cem_msg_t cem_msg = {0};
    uint32_t max_charge_vol = 0;        /* 最高允许充电电压 */
    uint32_t batt_curr_vol = 0;         /* BMS当前电压 */

    switch (config->config_fsm.status)
    {
    case CONFIG_IDLE_STATE:
        log_d("config idle.");
        clear_timer(&config->timer[0]);
        set_timer(&config->timer[0], 0, 5000);
        config->config_fsm.status = CONFIG_TSS_STATE;
        break;
    case CONFIG_TSS_STATE:
        RUN_PERIODIC_TASK(charge_send_cts(), CTS_MESSAGE_PER);
        RUN_PERIODIC_TASK(charge_send_cml(), CML_MESSAGE_PER);
        if (xTaskCheckTickTimeout(config->timer[0].end_tick))
        {
            retry++;
            if (retry >= 3)
            {
                retry = 0;
                ret = FSM_FAIL;
                general_cmd_map_get(CMD_MAP_CHARGE, CHARGE_ERR_CODE, cem_msg.buf, 4u);
                cem_msg.data.byte1.bro_timeout = pdTRUE;
                general_cmd_map_set(CMD_MAP_CHARGE, CHARGE_ERR_CODE, cem_msg.buf, 4u);
                clear_timer(&config->timer[0]);
                config->config_fsm.status = CONFIG_END_STATE;
            }
            else
            {
                clear_timer(&config->timer[0]);
                set_timer(&config->timer[0], 0, 5000);
            }
        }
        else if (config->msg->j1939_bms.addr.pgn == BMS_BRO_PGN)
        {
            if (config->msg->data.buf[0] == 0x00)
            {
                clear_timer(&config->timer[0]);
                set_timer(&config->timer[0], 0, 60000);
            }
            else if (config->msg->data.buf[0] == 0xAA)
            {
                retry = 0;
                clear_timer(&config->timer[0]);
                set_timer(&config->timer[0], 0, 5000);
                config->config_fsm.status = CONFIG_CRO00_STATE;
            }
        }
        break;
    case CONFIG_CRO00_STATE:
        RUN_PERIODIC_TASK(charge_send_cro(0x00), CRO_MESSAGE_PER);
        /* 判断继电器外侧电压和BMS的电压差值是否在规定范围内，目前外侧电压采集不到无法判断@WebbSu */
        general_cmd_map_get(CMD_MAP_BMS, BMS_MAX_VOLTAGE, (uint8_t *)&max_charge_vol, 4u);
        general_cmd_map_get(CMD_MAP_BMS, BMS_CURR_VOL, (uint8_t *)&batt_curr_vol, 4u);

        if ((batt_curr_vol >= PWR_MIN_OUT_VOL && batt_curr_vol < PWR_MAX_OUT_VOL) &&
                (max_charge_vol >= PWR_MIN_OUT_VOL && max_charge_vol < PWR_MAX_OUT_VOL))
        {
            undata32_t undata32 = {0};
            uint16_t power_on = PWR_POWER_ON; /* 开机 */
            uint32_t pre_vol = 0;
            uint32_t vol = 0, curr = 0;
            app_t *cfg = NULL;
            id_t id_x = {0};
            
            cfg = rt_container_of(config, app_t, bms);
            id_x.canid = cfg->pwr.msg->canid;
            general_cmd_map_get(CMD_MAP_BMS, BMS_CURR_VOL, (uint8_t *)&pre_vol, 2u);
            
            pre_vol *= 100;                 /* 转换成mV */
            pre_vol -= PRECHARGE_OFFSET;    /* 当前电压小于10V预充 */
            curr = 15 * 1000;               /* 设置预充电流15A */
            /* 设置功率模块参数然后开机 */
            if (!cfg->pwr.set.enable)
            {
                cfg->pwr.set.enable = pdTRUE;
                general_cmd_map_set(CMD_MAP_PWR, PWR_OUT_VOL, (uint8_t *)&pre_vol, 4u);
                general_cmd_map_set(CMD_MAP_PWR, PWR_OUT_CURR, (uint8_t *)&curr, 4u);
                power_on = PWR_POWER_ON;
                general_cmd_map_set(CMD_MAP_PWR, PWR_POWER_ON, (uint8_t *)&power_on, 2u);
            }

            if (id_x.id.cmd == READ_SYS_VOLTAGE_CMD)
            {
                undata32.data8[3] = cfg->pwr.msg->buf[0];
                undata32.data8[2] = cfg->pwr.msg->buf[1];
                undata32.data8[1] = cfg->pwr.msg->buf[2];
                undata32.data8[0] = cfg->pwr.msg->buf[3];
                vol = (uint32_t)(h_to_f(undata32.data32) * 1000.0f);
                log_d("pre_vol %d, vol %d", pre_vol, vol);
                if (abs(pre_vol - vol) <= TARGET_ERROR)
                {
                    relay_ctrl(RELAY_K1, ON);
                    relay_ctrl(RELAY_K2, ON);
                    clear_timer(&config->timer[0]);
                    set_timer(&config->timer[0], 0, 1000);
                    config->config_fsm.status = CONFIG_CROAA_STATE;
                }
            }
        }
        else
        {
            ret = FSM_FAIL;
            log_e("vol error.");
            clear_timer(&config->timer[0]);
            config->config_fsm.status = CONFIG_END_STATE;
        }
        break;
    case CONFIG_CROAA_STATE:
        RUN_PERIODIC_TASK(charge_send_cro(0xAA), CRO_MESSAGE_PER);
        if (xTaskCheckTickTimeout(config->timer[0].end_tick))
        {
            retry++;
            if (retry >= 3)
            {
                retry = 0;
                ret = FSM_FAIL;
                general_cmd_map_get(CMD_MAP_CHARGE, CHARGE_ERR_CODE, cem_msg.buf, 4u);
                cem_msg.data.byte2.bcl_timeout = pdTRUE;
                general_cmd_map_set(CMD_MAP_CHARGE, CHARGE_ERR_CODE, cem_msg.buf, 4u);
                log_e("send CRO AA timeouts.");
                clear_timer(&config->timer[0]);
                config->config_fsm.status = CONFIG_END_STATE;
            }
            else
            {
                clear_timer(&config->timer[0]);
                set_timer(&config->timer[0], 0, 1000);
            }
        }
        else if (config->msg->j1939_bms.addr.pgn == BMS_BCL_PGN)
        {
            app_t *cfg = NULL;
            
            retry = 0;
            ret = FSM_SUCCESS;
            log_d("recv PGN 0x1000.");

            cfg = rt_container_of(config, app_t, bms);
            cfg->charge_time.start_timestamp = xTaskGetTickCount();
            config->config_fsm.status = CONFIG_IDLE_STATE;
            clear_timer(&config->timer[0]);
        }
        break;
    case CONFIG_END_STATE:
        config->config_fsm.status = CONFIG_IDLE_STATE;
        break;
    default:
        break;
    }
    return ret;
}

/**
 * @brief                   充电握手阶段状态机
 * @param  shake            充电握手阶段操作对象
 * @return int              FSM_RUN：状态机运行  FSM_SUCCESS: 状态机完成  FSM_FAIL: 状态机出错
 */
static int shake_fsm(bms_t *const shake)
{
    int ret = FSM_RUN;
    static int retry = 0;

    switch (shake->shake_fsm.status)
    {
    case SHAKE_IDLE_STATE:
        /* 闭合K3 K4继电器 */
        log_d("shake idle.");
        relay_ctrl(RELAY_K3, ON);
        relay_ctrl(RELAY_K4, ON);
        clear_timer(&shake->timer[0]);
        set_timer(&shake->timer[0], 0, 5000);
        shake->shake_fsm.status = SHAKE_START_STATE;
        break;
    case SHAKE_START_STATE:
        RUN_PERIODIC_TASK(charge_send_chm(), CHM_MESSAGE_PER);
        if (xTaskCheckTickTimeout(shake->timer[0].end_tick))
        {
            log_e("recv BHM message timeout 5S.");
            retry++;
            if (retry >= 3)
            {
                retry = 0;
                ret = FSM_FAIL;
                shake->shake_fsm.status = SHAKE_END_STATE;
            }
            else
            {
                relay_ctrl(RELAY_K3, OFF);
                relay_ctrl(RELAY_K4, OFF);
                osDelay(100);
                shake->shake_fsm.status = SHAKE_IDLE_STATE;
            }
        }
        else if (shake->msg->j1939_bms.addr.pgn == BMS_BHM_PGN) /* recv BMS BRM message */
        {
            bhm_msg_t bhm_msg = {0};
            
            retry = 0;
            ret = FSM_SUCCESS;
            log_d("recv BHM message success. %04x", shake->msg->data.buf[1] << 8 | shake->msg->data.buf[0]);
            memcpy(bhm_msg.buf, shake->msg->data.buf, shake->msg->data.len);
            general_cmd_map_set(CMD_MAP_BMS, BMS_MAX_VOLTAGE, bhm_msg.buf, 2u);
            clear_timer(&shake->timer[0]);
            set_timer(&shake->timer[0], 0, 10000);
            shake->shake_fsm.status = SHAKE_IDLE_STATE;
        }
        break;
    case SHAKE_END_STATE:
        shake->shake_fsm.status = SHAKE_IDLE_STATE;
        break;
    default:
        break;
    }
    return ret;
}

/**
 * @brief                   充电阶段状态机
 * @param  charging         充电阶段操作对象
 * @return int              FSM_RUN：状态机运行  FSM_SUCCESS: 状态机完成  FSM_FAIL: 状态机出错
 */
static int charging_fsm(bms_t *const charging)
{
    int ret = FSM_RUN;
    cem_msg_t cem_msg = {0};
    static uint32_t back_vol = 0;
    static int retry = 0;
    static uint32_t vol = 0, curr = 0;

    /* CCS的报文发送逻辑 */
    {
        app_t *ccs = NULL;
        id_t id_x = {0};
        undata32_t undata32 = {0};

        ccs = rt_container_of(charging, app_t, bms);
        if (ccs != NULL)
        {
            id_x.canid = ccs->pwr.msg->canid;
            if (id_x.id.cmd == READ_SYS_VOLTAGE_CMD)
            {
                undata32.data8[3] = ccs->pwr.msg->buf[0];
                undata32.data8[2] = ccs->pwr.msg->buf[1];
                undata32.data8[1] = ccs->pwr.msg->buf[2];
                undata32.data8[0] = ccs->pwr.msg->buf[3];
                vol = undata32.data32;

                undata32.data8[3] = ccs->pwr.msg->buf[4];
                undata32.data8[2] = ccs->pwr.msg->buf[5];
                undata32.data8[1] = ccs->pwr.msg->buf[6];
                undata32.data8[0] = ccs->pwr.msg->buf[7];
                curr = undata32.data32;
            }
        }
        RUN_PERIODIC_TASK(charge_send_ccs(vol, curr, 1000), 50u);       /* CCS报文发送 */
    }

    switch (charging->charg_fsm.status)
    {
    case CHARGING_IDLE_STATE:
        clear_timer(&charging->timer[0]);
        set_timer(&charging->timer[0], 0, 1000);
        charging->charg_fsm.status = CHARGING_BCL_STATE;
        break;
    case CHARGING_BCL_STATE:
        if (xTaskCheckTickTimeout(charging->timer[0].end_tick))
        {
            retry++;
            if (retry >= 3)
            {
                retry = 0;
                log_e("charge BCL message timeouts");
                ret = FSM_FAIL;
                general_cmd_map_get(CMD_MAP_CHARGE, CHARGE_ERR_CODE, cem_msg.buf, 4u);
                cem_msg.data.byte2.bcl_timeout = pdTRUE;
                general_cmd_map_set(CMD_MAP_CHARGE, CHARGE_ERR_CODE, cem_msg.buf, 4u);
                clear_timer(&charging->timer[0]);
                charging->charg_fsm.status = CHARGING_END_STATE;
            }
            else
            {
                clear_timer(&charging->timer[0]);
                set_timer(&charging->timer[0], 0, 1000);
            }
        }
        else if (charging->msg->j1939_bms.addr.pgn == BMS_BCL_PGN)
        {
            bcl_msg_t bcl_msg = {0};
            app_t *bcl = NULL;
            uint32_t charge_state = 0;
            uint16_t power_on = 0;

            retry = 0;
            charge_state = CHARGEING;
            general_cmd_map_set(CMD_MAP_CHARGE, CHARGE_STATE, (uint8_t *)&charge_state, 4u);
            memcpy(bcl_msg.buf, charging->msg->data.buf, sizeof(bcl_msg.buf));
            vol = bcl_msg.data.voltage * 100;                       /* +mV */
            curr = (400.0f - (bcl_msg.data.curr * 0.1f)) * 1000;    /* +mA */
            log_w("bms vol %.2f  bms curr %.2f", bcl_msg.data.voltage * 0.1f, 400.0f - (bcl_msg.data.curr * 0.1f));
            log_w("vol %d  curr %d", vol, curr);
            /* 功率输出电压限幅 */
            if ((vol > PWR_MAX_OUT_VOL * 100)) {
                vol = PWR_MAX_OUT_VOL * 100;
            }

            /* 功率输出电流限幅 */
            if (curr > PWR_MAX_OUT_CURR * 100) {
                curr = PWR_MAX_OUT_CURR * 100;
            }

            back_vol = vol;
            bcl = rt_container_of(charging, app_t, bms);
            if (!bcl->pwr.set.enable)
            {
                bcl->pwr.set.enable = pdTRUE;
                power_on = PWR_POWER_ON;
                general_cmd_map_set(CMD_MAP_PWR, PWR_POWER_ON, (uint8_t *)&power_on, 2u);
                general_cmd_map_set(CMD_MAP_PWR, PWR_OUT_VOL, (uint8_t *)&vol, 4u);
                general_cmd_map_set(CMD_MAP_PWR, PWR_OUT_CURR, (uint8_t *)&curr, 4u);
            }
            clear_timer(&charging->timer[0]);
            set_timer(&charging->timer[0], 0, 5000);
            charging->charg_fsm.status = CHARGING_BCS_STATE;
        }
        break;
    case CHARGING_BCS_STATE:
        if (xTaskCheckTickTimeout(charging->timer[0].end_tick))
        {
            retry++;
            if (retry >= 3)
            {
                retry = 0;
                log_e("charge BCS message timeouts");
                ret = FSM_FAIL;
                general_cmd_map_get(CMD_MAP_CHARGE, CHARGE_ERR_CODE, cem_msg.buf, 4u);
                cem_msg.data.byte2.bcs_timeout = pdTRUE;
                general_cmd_map_set(CMD_MAP_CHARGE, CHARGE_ERR_CODE, cem_msg.buf, 4u);
                clear_timer(&charging->timer[0]);
                charging->charg_fsm.status = CHARGING_END_STATE;
            }
            else
            {
                clear_timer(&charging->timer[0]);
                set_timer(&charging->timer[0], 0, 5000);
            }
        }
        else if (charging->msg->j1939_bms.addr.pgn == BMS_BCS_PGN)
        {
            bcs_msg_t bcs_msg = {0};

            retry = 0;
            memcpy(bcs_msg.buf, charging->msg->data.buf, sizeof(bcs_msg.buf));
            log_d("bcs soc %d", bcs_msg.data.soc);
            log_d("bcs real time %d", bcs_msg.data.rema_time);
            general_cmd_map_set(CMD_MAP_BMS, BMS_BATT_SOC, (uint8_t *)&bcs_msg.data.soc, 2);
            general_cmd_map_set(CMD_MAP_BMS, BMS_REMAIN_TIME, (uint8_t *)&bcs_msg.data.rema_time, 4);
        }
        else if (charging->msg->j1939_bms.addr.pgn == BMS_BSM_PGN)
        {
            bsm_msg_t bsm_msg = {0};
            
            memcpy(bsm_msg.buf, charging->msg->data.buf, sizeof(bsm_msg.buf));
            log_d("max batt temp %d", SIGNAL_TO_PHY(2, bsm_msg.data.max_batt_temp, -50, 0));
            log_d("min batt temp %d", SIGNAL_TO_PHY(2, bsm_msg.data.min_batt_temp, -50, 0));
            log_d("max temp num  %d", bsm_msg.data.max_temp_num);
            log_d("min temp num  %d", bsm_msg.data.min_temp_num);
            
            if (bsm_msg.data.bit_convert.data.charge_en == 0x00)    /* BMS端充电暂停 */
            {
                /* 设置功率模块输出电流为0 */
                uint16_t power_on = 0;
                app_t *bsm = NULL;

                bsm = rt_container_of(charging, app_t, bms);
                if (!bsm->pwr.set.enable)
                {
                    bsm->pwr.set.enable = pdTRUE;
                    power_on = PWR_POWER_ON;
                    vol = back_vol;
                    curr = 0;
                    general_cmd_map_set(CMD_MAP_PWR, PWR_POWER_ON, (uint8_t *)&power_on, 2u);
                    general_cmd_map_set(CMD_MAP_PWR, PWR_OUT_VOL, (uint8_t *)&vol, 4u);
                    general_cmd_map_set(CMD_MAP_PWR, PWR_OUT_CURR, (uint8_t *)&curr, 4u);
                }
                log_e("charge stop.");
                charging->charg_fsm.status = CHARGING_SUSPEND_STATE;
                break;
            }
            charging->charg_fsm.status = CHARGING_JUDGE_STATE;
        }
        break;
    case CHARGING_SUSPEND_STATE:
        if (charging->msg->j1939_bms.addr.pgn == BMS_BSM_PGN)
        {
            bsm_msg_t bsm_msg = {0};
            
            memcpy(bsm_msg.buf, charging->msg->data.buf, sizeof(bsm_msg.buf));
            if (bsm_msg.data.bit_convert.data.charge_en == 0x01)
            {
                charging->charg_fsm.status = CHARGING_JUDGE_STATE;
            }            
        }
        break;
    case CHARGING_JUDGE_STATE:
        charging->charg_fsm.status = CHARGING_IDLE_STATE;
        break;
    case CHARGING_END_STATE:
        charging->charg_fsm.status = CHARGING_IDLE_STATE;
        break;
    default:
        break;
    }
    return ret;
}

/**
 * @brief                   充电结束状态处理
 * @param  end              充电结束操作对象
 * @return int              FSM_RUN：状态机运行  FSM_SUCCESS: 状态机完成  FSM_FAIL: 状态机出错
 */
int end_fsm(app_t *const end)
{
    int ret = FSM_RUN;
    uint16_t power_on = PWR_POWER_OFF;
    uint32_t set_out_value = 0, set_out_curr = 0;
    uint16_t charge_end_ctrl = 0;

    id_t id_x = {0};
    undata32_t undata32 = {0};
    uint16_t fault_code = 0;
    uint32_t cst_data  = 0;
    uint32_t charge_state = 0;
    cst_msg_t cst_msg = {0};

    static int retry = 0;
    static int charge_stop_flag = 0;

    switch (end->bms.end_fsm.status)
    {
    case ENDING_IDLE_STATE_STATE:
        /* 区分正常结束充电还是异常结束，执行不同的逻辑处理@WebbSu */
        general_cmd_map_get(CMD_MAP_CHARGE, CHARGE_FAULT_CODE, (uint8_t *)&fault_code, 2u);
        if (fault_code != 0)
        {
            log_e("fault code != 0. %02x", fault_code);
            /* 非车辆原因 */
            if ((fault_code & (CHARGE_K1K2_FAULT |\
                                CAHAGE_CC1_FAULT | \
                                CHARGE_IDF_FAULT | \
                                CHARGE_PE_FAULT)) != 0)
            {
                charge_stop_flag = pdTRUE;
                general_cmd_map_get(CMD_MAP_CHARGE, CHARGE_END_CAUSE, cst_msg.buf, sizeof(cst_msg.buf));
                cst_msg.data.end.fault = pdTRUE;
                cst_msg.data.fault.other_fault = pdTRUE;
                general_cmd_map_set(CMD_MAP_CHARGE, CHARGE_END_CAUSE, cst_msg.buf, sizeof(cst_msg.buf));
                clear_timer(&end->bms.timer[0]);
                set_timer(&end->bms.timer[0], 0, 5000);
            }
            else
            {
                clear_timer(&end->bms.timer[0]);
                set_timer(&end->bms.timer[0], 0, 10000);
            }
        }
        else
        {
                clear_timer(&end->bms.timer[0]);
                set_timer(&end->bms.timer[0], 0, 5000);
        }

        end->bms.end_fsm.status = ENDING_SEND_CST_STATE;
        end->charge_time.time = xTaskGetTickCount() - end->charge_time.start_timestamp;
        end->charge_time.time = (uint32_t)((end->charge_time.time / 1000) / 60);
        general_cmd_map_set(CMD_MAP_CHARGE, ONCE_CHARGE_TIME, (uint8_t *)&end->charge_time.time, 4u);
        break;
    case ENDING_SEND_CST_STATE:
		general_cmd_map_get(CMD_MAP_CHARGE, CHARGE_END_CAUSE, (uint8_t *)&cst_data, 4u);
		memcpy((uint8_t *)cst_msg.buf, (uint8_t *)&cst_data, sizeof(cst_data));
		RUN_PERIODIC_TASK(charge_send_cst(cst_data), CST_MESSAGE_PER);
		if (xTaskCheckTickTimeout(end->bms.timer[0].end_tick))
		{
            cem_msg_t cem_msg = {0};
            if (charge_stop_flag)
            {
            	general_cmd_map_get(CMD_MAP_CHARGE, CHARGE_ERR_CODE, cem_msg.buf, 4u);
                cem_msg.data.byte2.bst_timeout = pdTRUE;
                log_d("recv BST timeout.");
                general_cmd_map_set(CMD_MAP_CHARGE, CHARGE_ERR_CODE, cem_msg.buf, 4u);
            }
            else
            {
                general_cmd_map_get(CMD_MAP_CHARGE, CHARGE_ERR_CODE, cem_msg.buf, 4u);
                cem_msg.data.byte3.bsd_timeout = pdTRUE;
                log_d("recv BSD timeout.");
                general_cmd_map_set(CMD_MAP_CHARGE, CHARGE_ERR_CODE, cem_msg.buf, 4u);
            }
            end->bms.end_fsm.status = ENDING_SEND_CEM_STATE;
		}

        if (cst_msg.data.end.bms == pdTRUE)
        {
        	if (end->bms.msg->j1939_bms.addr.pgn == BMS_BSD_PGN)
        	{
        		log_d("recv BSD Success.");
        		end->bms.end_fsm.status = ENDING_SEND_CSD_STATE;
        	}
        }
        break;
    case ENDING_SEND_CSD_STATE:
        RUN_PERIODIC_TASK(charge_send_csd(), CSD_MESSAGE_PER);
        if (xTaskCheckTickTimeout(end->bms.timer[0].end_tick))
        {
            cem_msg_t cem_msg = {0};
            general_cmd_map_get(CMD_MAP_CHARGE, CHARGE_ERR_CODE, cem_msg.buf, 4u);
            cem_msg.data.byte3.bsd_timeout = pdTRUE;
            general_cmd_map_set(CMD_MAP_CHARGE, CHARGE_ERR_CODE, cem_msg.buf, 4u);
            retry++;
            if (retry >= 3)
            {
                retry = 0;
                general_cmd_map_get(CMD_MAP_CHARGE, CHARGE_ERR_CODE, cem_msg.buf, 4u);
                cem_msg.data.byte3.bsd_timeout = pdTRUE;
                log_d("recv BSD timeout.");
                general_cmd_map_set(CMD_MAP_CHARGE, CHARGE_ERR_CODE, cem_msg.buf, 4u);
                end->bms.end_fsm.status = ENDING_SEND_CEM_STATE;
            }
        }
        else if (end->bms.msg->j1939_bms.addr.pgn == BMS_BSD_PGN)
        {
            bsd_msg_t bsd_msg = {0};

            memcpy(bsd_msg.buf, end->bms.msg->data.buf, sizeof(bsd_msg.buf));
            log_d("*******************************");
            log_d("end_soc %d", bsd_msg.data.end_soc);
            log_d("min_one_charge_vol %d", bsd_msg.data.min_one_charge_vol);
            log_d("max_one_charge_vol %d", bsd_msg.data.max_one_charge_vol);
            log_d("min_temp %d", bsd_msg.data.min_temp);
            log_d("max_temp %d", bsd_msg.data.max_temp);
            log_d("*******************************");
            clear_timer(&end->bms.timer[0]);
            set_timer(&end->bms.timer[0], 0, 5000); /* 国标要求100ms内电流要下降到5A以下 */
            end->bms.end_fsm.status = ENDING_CLOSE_PWR_STATE;
        }
        break;
    case ENDING_SEND_CEM_STATE:
        charge_send_cem();
        end->bms.end_fsm.status = ENDING_CLOSE_PWR_STATE;
        break;
    case ENDING_CLOSE_PWR_STATE:
        charge_send_cem();
        if (xTaskCheckTickTimeout(end->bms.timer[0].end_tick))
        {
            clear_timer(&end->bms.timer[0]);
            set_timer(&end->bms.timer[0], 0, 5000);
            end->bms.end_fsm.status = ENDING_RP_STATE;
            break;
        }

        if (!end->pwr.set.enable)
        {
            end->pwr.set.enable = pdTRUE;
            power_on = PWR_POWER_OFF;                                                                 
            general_cmd_map_set(CMD_MAP_PWR, PWR_OUT_VOL, (uint8_t *)&set_out_value, 4u); /* 设置绝缘检测模块的输出 */
            general_cmd_map_set(CMD_MAP_PWR, PWR_OUT_CURR, (uint8_t *)&set_out_curr, 4u); /* 设置功率模块的输出电流 */
            general_cmd_map_set(CMD_MAP_PWR, PWR_POWER_ON, (uint8_t *)&power_on, 2u);     /* 关机 */
        }

        id_x.canid = end->pwr.msg->canid;
        if (id_x.id.cmd == READ_SYS_VOLTAGE_CMD)
        {
            float curr_f = 0.0f;
            undata32.data8[3] = end->pwr.msg->buf[4];
            undata32.data8[2] = end->pwr.msg->buf[5];
            undata32.data8[1] = end->pwr.msg->buf[6];
            undata32.data8[0] = end->pwr.msg->buf[7];
            curr_f = h_to_f(undata32.data32);
            if ((int)(curr_f * 1000.0f) <= 5000 || undata32.data32 == 0) /* 电流小于5A */
            {
                log_d("curr %.2f < 5A.", curr_f);
                relay_ctrl(RELAY_K1, OFF);
                relay_ctrl(RELAY_K2, OFF);
                clear_timer(&end->bms.timer[0]);
                set_timer(&end->bms.timer[0], 0, 5000);
                end->bms.end_fsm.status = ENDING_RP_STATE;
            }
        }
        break;
    case ENDING_RP_STATE:
        if (xTaskCheckTickTimeout(end->bms.timer[0].end_tick))
        {
            log_e("RP timeouts.");
            retry++;
            if (retry >= 3)
            {
                retry = 0;
                end->bms.end_fsm.status = ENDING_OPEN_ELE_LOCK_STATE;
                break;
            }
            clear_timer(&end->bms.timer[0]);
            set_timer(&end->bms.timer[0], 0, 5000); /* 国标要求100ms内电流要下降到5A以下 */
            break;
        }

        if (!end->pwr.set.enable)
        {
            end->pwr.set.enable = pdTRUE;
            power_on = PWR_POWER_OFF;                                                                 
            general_cmd_map_set(CMD_MAP_PWR, PWR_OUT_VOL, (uint8_t *)&set_out_value, 4u); /* 设置绝缘检测模块的输出 */
            general_cmd_map_set(CMD_MAP_PWR, PWR_OUT_CURR, (uint8_t *)&set_out_curr, 4u); /* 设置功率模块的输出电流 */
            general_cmd_map_set(CMD_MAP_PWR, PWR_POWER_ON, (uint8_t *)&power_on, 2u);     /* 关机 */
        }
        
        id_x.canid = end->pwr.msg->canid;
        if (id_x.id.cmd == READ_SYS_VOLTAGE_CMD)
        {
            undata32.data8[3] = end->pwr.msg->buf[0];
            undata32.data8[2] = end->pwr.msg->buf[1];
            undata32.data8[1] = end->pwr.msg->buf[2];
            undata32.data8[0] = end->pwr.msg->buf[3];
            if ((uint32_t)(h_to_f(undata32.data32) * 1000.0f) < 60 * 1000 || undata32.data32 == 0) /* 如果K1K2外侧继电器电压小于60V */
            {
                log_d("vol < 60V.");
                relay_ctrl(RELAY_K3, OFF);
                relay_ctrl(RELAY_K4, OFF);
                end->bms.end_fsm.status = ENDING_OPEN_ELE_LOCK_STATE;
            }
        }
        break;
    case ENDING_OPEN_ELE_LOCK_STATE:
        /* 电子锁控制解锁 */
        log_e("ELE LOCK OPEN.");
        ele_lock_open();
        charge_stop_flag = 0;
        charge_end_ctrl = 0;
        general_cmd_map_set(CMD_MAP_CHARGE, CHARGE_CTRL, (uint8_t *)&charge_end_ctrl, 2u);
        charge_state = CHARGE_END;
        general_cmd_map_set(CMD_MAP_CHARGE, CHARGE_STATE, (uint8_t *)&charge_state, 4u);
        /* 清除充电结束的原因 */
        cst_data = 0;
        general_cmd_map_set(CMD_MAP_CHARGE, CHARGE_END_CAUSE, (uint8_t *)&cst_data, 4u);
        /* 清除错误码 */
        undata32.data32 = 0;
        general_cmd_map_set(CMD_MAP_CHARGE, CHARGE_ERR_CODE, undata32.data8, 4u);
        ret = FSM_SUCCESS;
        end->bms.end_fsm.status = ENDING_IDLE_STATE_STATE;
        break;
    default:
        break;
    }
    return ret;
}

/**
 * @brief                   充电引导总体状态机
 * @param  params           充电主流程操作对象
 * @return int              FSM_RUN：状态机运行  FSM_SUCCESS: 状态机完成  FSM_FAIL: 状态机出错
 */
static int charge_fsm(app_t *const params)
{
    int ret = FSM_RUN;
    bms_t *bms_obj = (bms_t *)&params->bms;
    
    static uint32_t max_charge_vol = 0, set_out_curr = 0, set_out_value = 0, power_on = PWR_POWER_OFF;
    static int ins_step = 0;
    static int cc1_last = 0;
    static int gun_valid = 0;
    uint16_t charge_start_ctrl = 0;
    uint16_t charge_mode = 0;

    switch (params->status)
    {
    case CHARGE_IDLE_STATE:
        cc1_last = get_cc1_state();
        if (cc1_last != 0)
            params->status = CHARGE_START_STATE;
        break;
    case CHARGE_START_STATE:
        general_cmd_map_get(CMD_MAP_CHARGE, CHARGE_CTRL, (uint8_t *)&charge_start_ctrl, 2u);
        general_cmd_map_get(CMD_MAP_CHARGE, CHARGE_MODE, (uint8_t *)&charge_mode, 2u);
        if (get_cc1_state() != cc1_last)
        {
            /* 锁定电子锁, 等待电子锁锁止成功@WebbSu需要添加控制电子锁的API */
            if (get_cc1_state() == CC1_4V_STATE && cc1_last == CC1_6V_STATE)
            {
                // if (charge_mode == 3)
                {
                    ele_lock_close();
                    params->status = CHARGE_SHAKE_STATE;
                }
                gun_valid = 1;
            }
            else
            {
                params->status = CHARGE_IDLE_STATE;
            }
        }
        cc1_last = get_cc1_state();

        // if (charge_start_ctrl == 1 && gun_valid == 1)
        // {
        //     gun_valid = 0;
        //     ele_lock_close();
        //     params->status = CHARGE_SHAKE_STATE;
        // }
        break;
    case CHARGE_SHAKE_STATE:
        ret = shake_fsm(bms_obj);
        if (ret == FSM_SUCCESS)
            params->status = CHARGE_INSU_STATE;
        else if (ret == FSM_FAIL)
            params->status = CHARGE_END_STATE;
        break;
    case CHARGE_INSU_STATE:
        if (xTaskCheckTickTimeout(bms_obj->timer[0].end_tick))
        {
            ins_step = 0;
            event_clear_bit(ENABLE_INS_EVT);
            params->status = CHARGE_END_STATE;
        }
        else
        {
            id_t id_x = {0};
            uint32_t vol = 0;
            undata32_t undata32 = {0};

            /* 设置功率模块参数然后开机 */
            if (!params->pwr.set.enable)
            {
                params->pwr.set.enable = pdTRUE;
                general_cmd_map_get(CMD_MAP_BMS, BMS_MAX_VOLTAGE, (uint8_t *)&max_charge_vol, 4u);
                set_out_value = min(max_charge_vol, INS_VOL);
                set_out_value *= 100;
                power_on = PWR_POWER_ON;
                set_out_curr = INS_CURR;
                general_cmd_map_set(CMD_MAP_PWR, PWR_OUT_VOL, (uint8_t *)&set_out_value, 4u); /* 设置绝缘检测模块的输出 */
                general_cmd_map_set(CMD_MAP_PWR, PWR_OUT_CURR, (uint8_t *)&set_out_curr, 4u); /* 设置功率模块的输出电流 */
                general_cmd_map_set(CMD_MAP_PWR, PWR_POWER_ON, (uint8_t *)&power_on, 2u);     /* 功率模块开机 */
            }

            /* 查询功率模块当前的输出电压 */
            id_x.canid = params->pwr.msg->canid;
            if (id_x.id.cmd == READ_SYS_VOLTAGE_CMD)
            {
                undata32.data8[3] = params->pwr.msg->buf[0];
                undata32.data8[2] = params->pwr.msg->buf[1];
                undata32.data8[1] = params->pwr.msg->buf[2];
                undata32.data8[0] = params->pwr.msg->buf[3];
                vol = (uint32_t)(h_to_f(undata32.data32) * 1000.0f);
                if (0 == ins_step)
                {
                    if (abs(set_out_value - vol) <= TARGET_ERROR)
                    {
                        log_d("set_out_value %d, vol %d", set_out_value, vol);
                        if (event_get_bit(ENABLE_INS_EVT) != 1)
                            event_set_bit(ENABLE_INS_EVT);
                        relay_ctrl(RELAY_K1, ON);
                        relay_ctrl(RELAY_K2, ON);
                        ins_step = 1;
                    }
                }
            }
            
            if (1 == ins_step)
            {
                if (get_ins_state())
                {
                    ins_step = 2;
                    event_clear_bit(ENABLE_INS_EVT);
                    /* 泄放电路使能，关闭功率模块 */
                    if (!params->pwr.set.enable)
                    {
                        params->pwr.set.enable = pdTRUE;
                        set_out_value = 0;
                        set_out_curr = 0;
                        power_on = PWR_POWER_OFF;   /* 关机 */
                        general_cmd_map_set(CMD_MAP_PWR, PWR_OUT_VOL, (uint8_t *)&set_out_value, 4u); /* 设置绝缘检测模块的输出 */
                        general_cmd_map_set(CMD_MAP_PWR, PWR_OUT_CURR, (uint8_t *)&set_out_curr, 4u); /* 设置功率模块的输出电流 */
                        general_cmd_map_set(CMD_MAP_PWR, PWR_POWER_ON, (uint8_t *)&power_on, 2u);     /* 功率模块开机 */
                    }
                    log_d("ins detection success.");
                }
            }
            else if (2 == ins_step)
            {
                if (vol <= 60 * 1000)   /* 泄放到电压小于60V */
                {
                	log_d("INS RP VOL < 60V.");
                    ins_step = 0;
                	params->status = CHARGE_IDENTIFY_STATE;
                }
            }
        }
        break;
    case CHARGE_IDENTIFY_STATE:
        ret = identify_fsm(bms_obj);
        if (ret == FSM_SUCCESS)
            params->status = CHARGE_CONFIG_STATE;
        else if (ret == FSM_FAIL)
            params->status = CHARGE_END_STATE;
        break;
    case CHARGE_CONFIG_STATE:
        ret = config_fsm(bms_obj, params->pwr.msg);
        if (ret == FSM_SUCCESS)
            params->status = CHARGE_KEEP_STATE;
        else if (ret == FSM_FAIL)
            params->status = CHARGE_END_STATE;
        break;
    case CHARGE_KEEP_STATE:
        ret = charging_fsm(bms_obj);
        if (ret == FSM_FAIL || ret == FSM_SUCCESS)
            params->status = CHARGE_END_STATE;
        break;
    case CHARGE_END_STATE:
        ret = end_fsm(params);
        if (ret == FSM_SUCCESS || ret == FSM_FAIL)
        {
            apptask_init(params);
            params->status = CHARGE_IDLE_STATE;
        }
        break;
    default:
        break;
    }
    return ret;
}

/**
 * @brief                   BMS故障处理
 * @param  fault            故障处理对象
 * @return int              返回当前函数执行状态 0：success; <0: fail
 */
static int bms_fault(app_t *fault)
{
    int ret = 0;
    uint16_t bms_fault_code = 0;
    uint32_t fault_code = 0;

    if (fault->bms.msg->j1939_bms.addr.pgn == BMS_BST_PGN)
    {
        bst_msg_t bst_msg = {0};
        cst_msg_t cst_msg = {0};

        general_cmd_map_get(CMD_MAP_CHARGE, CHARGE_END_CAUSE, cst_msg.buf, sizeof(cst_msg.buf));
        cst_msg.data.end.bms = pdTRUE;
        log_d("recv BST success.");
        memcpy(bst_msg.buf, fault->bms.msg->data.buf, sizeof(bst_msg.buf));
        if (bst_msg.data.fault.end_charge_fault != 0) /* BMS充电故障处理 */
        {
            fault_code |= CHARGE_BMS_FAULT;
            bms_fault_code = bst_msg.data.fault.end_charge_fault;
            log_e("bms fault %04x", bst_msg.data.fault.end_charge_fault);
            log_e("bms fault 1 %d", bst_msg.data.fault.fault_bit.idf_fault);
            log_e("bms fault 2 %d", bst_msg.data.fault.fault_bit.out_conn_tempfault);
            log_e("bms fault 3 %d", bst_msg.data.fault.fault_bit.bms_out_temp_fault);
            log_e("bms fault 4 %d", bst_msg.data.fault.fault_bit.charge_conn_fault);
            log_e("bms fault 5 %d", bst_msg.data.fault.fault_bit.batt_temp_fault);
            log_e("bms fault 6 %d", bst_msg.data.fault.fault_bit.high_relay_fault);
            log_e("bms fault 7 %d", bst_msg.data.fault.fault_bit.det2_fault);
            log_e("bms fault 8 %d", bst_msg.data.fault.fault_bit.other_fault);
        }
        else
        {
            /* 没有故障正常结束充电 */
            fault_code &= ~CHARGE_BMS_FAULT;
        }
        general_cmd_map_set(CMD_MAP_CHARGE, CHARGE_END_CAUSE, cst_msg.buf, sizeof(cst_msg.buf));
        general_cmd_map_set(CMD_MAP_CHARGE, CHARGE_FAULT_CODE, (uint8_t *)&fault_code, sizeof(fault_code));
        fault->status = CHARGE_END_STATE;
    }
    return ret;
}

/**
 * @brief                   BMS错误处理
 * @param  err              BMS错误处理操作对象
 * @return int              返回当前函数执行状态 0：success  1：fail
 */
static int bms_error(app_t *err)
{
    int ret = 0;
    if (err->bms.msg->j1939_bms.addr.pgn == BMS_BST_PGN)
    {
        bst_msg_t bst_msg = {0};
        memcpy(bst_msg.buf, err->bms.msg->data.buf, sizeof(bst_msg.buf));
        if (bst_msg.data.end_charge_error != 0) /* BMS充电错误处理 */
        {
            log_e("bms error %04x", bst_msg.data.end_charge_error);
            err->status = CHARGE_END_STATE;
        }
    }
    else if (err->bms.msg->j1939_bms.addr.pgn == BMS_BEM_PGN)
    {
        
    }
    else if (err->bms.msg->j1939_bms.addr.pgn == BMS_BSM_PGN)
    {
        bsm_msg_t bsm_msg = {0};
        memcpy(bsm_msg.buf, err->bms.msg->data.buf, sizeof(bsm_msg.buf));
        if ((bsm_msg.data.bit_convert.buf[0] & 0xfff) != 0)
        {
            log_e("bms bsm error %04x", bsm_msg.data.bit_convert.buf[0]);
            log_e("over vol %d", bsm_msg.data.bit_convert.data.over_vol);
            log_e("over soc %d", bsm_msg.data.bit_convert.data.over_soc);
            log_e("over curr %d", bsm_msg.data.bit_convert.data.over_curr);
            log_e("over temp %d", bsm_msg.data.bit_convert.data.over_temp);
            log_e("ins state %d", bsm_msg.data.bit_convert.data.ins_state);
            log_e("conn state %d", bsm_msg.data.bit_convert.data.conn_state);
            log_e("charge en %d", bsm_msg.data.bit_convert.data.charge_en);
            // err->status = CHARGE_END_STATE;
        }
    }
    return ret;
}

/**
 * @brief                   电源模块故障处理
 * @param  fault            电源模块故障处理对象
 * @return int              返回当前函数执行状态 0：success; <0: fail
 */
static int pwr_fault(app_t *fault)
{
    int ret = 0;
    id_t id_x = {0};
    pwr_sta_0_t pwr_sta_0 = {0};
    pwr_sta_1_t pwr_sta_1 = {0};
    pwr_sta_2_t pwr_sta_2 = {0};
    uint16_t power_state = 0;

    id_x.canid = fault->pwr.msg->canid;
    if (id_x.id.cmd == READ_SYS_STATE_CMD)
    {
        pwr_sta_0.buf[0] = fault->pwr.msg->buf[7];
        pwr_sta_1.buf[0] = fault->pwr.msg->buf[6];
        pwr_sta_2.buf[0] = fault->pwr.msg->buf[5];
        /* 状态123可能出现了异常 */
        if (pwr_sta_0.data.out_sc || pwr_sta_1.data.conn_alarm || pwr_sta_2.data.in_over_vol || pwr_sta_0.data.conn_fault)
        {
            log_e("pwr fault || pwr alarm.");
            log_e("sta0 %02x, sta1 %02x, sta2 %02x", pwr_sta_0.buf[0], pwr_sta_1.buf[0], pwr_sta_2.buf[0]);
            fault->status = CHARGE_END_STATE;
        }
    }

    /* PWR CAN通讯超时@webbsu */
    general_cmd_map_get(CMD_MAP_PWR, PWR_POWER_ON, (uint8_t *)&power_state, 2u);
    if (!power_state) /* 开机状态 */
    {
        if (xTaskCheckTickTimeout(fault->pwr.timer[0].end_tick))
        {
            if (fault->pwr.timer[0].event == PWR_RECV_TIMEOUT)
            {
                log_e("pwr recv data timeout.");
            }
        }
    }
    return ret;
}

/**
 * @brief                   充电桩产生的错误处理
 * @param  err              桩端处理对象
 * @return int              返回当前函数执行状态 0：success; <0: fail
 */
static int charge_err(app_t *err)
{
    int ret = 0;
    id_t id_x = {0};
    undata32_t undata32 = {0};
    uint32_t bms_max_vol = 0;
    double charge_temp = 0.0;
    uint32_t charge_state = 0;
    uint16_t charge_end_ctrl = 0;

    general_cmd_map_get(CMD_MAP_BMS, BMS_MAX_VOLTAGE, (uint8_t *)&bms_max_vol, 4u);
    
    id_x.canid = err->pwr.msg->canid;
    if (id_x.id.cmd == READ_SYS_VOLTAGE_CMD)
    {
        /* 电源模块的字节序高字节在前 */
        undata32.data8[3] = err->pwr.msg->buf[0];
        undata32.data8[2] = err->pwr.msg->buf[1];
        undata32.data8[1] = err->pwr.msg->buf[2];
        undata32.data8[0] = err->pwr.msg->buf[3];
        if (((uint32_t)((float)h_to_f(undata32.data32) * 1000)) > (bms_max_vol * 100)+ 10000)            /* 超过BMS的最大充电允许电压 +mv */
        {
            /* 错误处理 */
            log_e("over BMS input vol. %d mv > %d mv", ((uint32_t)((float)h_to_f(undata32.data32) * 1000)), bms_max_vol * 100);
            err->status = CHARGE_END_STATE;
        }
    }

    /* 充电桩输出超过最大允许充电电压+10v，停止充电 */
    if (get_dc_bus_voltage() > (bms_max_vol * 100) + 10000)
    {
        cst_msg_t cst_msg = {0};
        general_cmd_map_get(CMD_MAP_CHARGE, CHARGE_END_CAUSE, cst_msg.buf, sizeof(cst_msg.buf));
        cst_msg.data.error.un_vol = pdTRUE;
        general_cmd_map_set(CMD_MAP_CHARGE, CHARGE_END_CAUSE, cst_msg.buf, sizeof(cst_msg.buf));
        log_e("over BMS input vol. %d mv > %d mv", get_dc_bus_voltage(), bms_max_vol * 100);
        err->status = CHARGE_END_STATE;
    }   

    /* 充电枪过温检测及过温处理@webbsu ，持续过温超过60S，暂停充电 */
    {
        static int flag = 0;
        static uint32_t tick = 0;

        charge_temp = get_ch1_temp();
        if (charge_temp >= OVER_TEMP_GATE)
        {
            if (!flag)
            {
                flag = pdTRUE;
                tick = xTaskGetTickCount();
            }
            else if (xTaskGetTickCount() - tick >= 60 * 1000)
            {
                // log_e("Overtemperature alarm.");
            }
        }
        else
        {
            flag = pdFALSE;
        }
    }
    
    /* 充电过程中，CC1检测错误和APP主动停止检测 */
    general_cmd_map_get(CMD_MAP_CHARGE, CHARGE_STATE, (uint8_t *)&charge_state, 4u);
    if (charge_state == CHARGEING)
    {
        general_cmd_map_set(CMD_MAP_CHARGE, CHARGE_CTRL, (uint8_t *)&charge_end_ctrl, 2u);
        // if (get_cc1_state() != CC1_4V_STATE || charge_end_ctrl == 0)
        if (get_cc1_state() != CC1_4V_STATE)
        {
            cst_msg_t cst_msg = {0};

            general_cmd_map_get(CMD_MAP_CHARGE, CHARGE_END_CAUSE, cst_msg.buf, sizeof(cst_msg.buf));
            cst_msg.data.end.fault = pdTRUE;
            cst_msg.data.fault.conn_fault = pdTRUE;
            general_cmd_map_set(CMD_MAP_CHARGE, CHARGE_END_CAUSE, cst_msg.buf, sizeof(cst_msg.buf));
            log_e("CC1 ERROR. || app end charge.");
            err->status = CHARGE_END_STATE;
        }
    }
    return ret;
}

/**
 * @brief                   充电桩产生的故障处理
 * @param  fault            桩端故障处理对象
 * @return int              返回当前函数执行状态 0：success; <0: fail
 */
static int charge_fault(app_t *fault)
{
    int ret = 0;
    uint32_t charge_fault_code = 0;

    /* 高压侧继电器故障, 继电器粘连故障 */
    if (get_relay_status() != 0)  
    {
        // log_e("high vol relay fault.");
        charge_fault_code |= CHARGE_K1K2_FAULT;
        general_cmd_map_set(CMD_MAP_CHARGE, CHARGE_FAULT_CODE, (uint8_t *)&charge_fault_code, sizeof(charge_fault_code));
        // fault->status = CHARGE_END_STATE;
    }

    /* 接地检测故障 */
    if (get_pe_state() < 0)
    {
        charge_fault_code |= CHARGE_PE_FAULT;
        general_cmd_map_set(CMD_MAP_CHARGE, CHARGE_FAULT_CODE, (uint8_t *)&charge_fault_code, sizeof(charge_fault_code)); 
        // fault->status = CHARGE_END_STATE;       
    }
    return ret;
}

/**
 * @brief                   主程序初始化
 * @param  init             初始对象
 */
static void apptask_init(app_t *init)
{   
    init->status                = CHARGE_IDLE_STATE;
    init->bms.charg_fsm.status  = CHARGING_IDLE_STATE;
    init->bms.config_fsm.status = CONFIG_IDLE_STATE;
    init->bms.iden_fsm.status   = IDENTIFY_IDLE_STATE;
    init->bms.shake_fsm.status  = SHAKE_IDLE_STATE;
    init->bms.end_fsm.status    = ENDING_IDLE_STATE_STATE;
}

/**
 * @brief                   充电引导主任务
 * @param  argument         FreeRTOS任务参数
 */
void apptask(void *argument)
{
    int bms_q_ret = 0, pwr_q_ret = 0;

    qmsg_t qmsg = {0};
    pwr_msg_t pmsg = {0};

    xSemaphoreTake(sync_sem, portMAX_DELAY);
    apptask_init(&app);

    for (;;)
    {
        // log_d("%d-%d-%d-%d", app.bms.shake_fsm.status, app.bms.iden_fsm.status, app.bms.config_fsm.status, app.bms.charg_fsm.status);
        if ((app.bms.shake_fsm.status != SHAKE_IDLE_STATE && app.bms.shake_fsm.status != SHAKE_END_STATE) || \
            (app.bms.iden_fsm.status != IDENTIFY_IDLE_STATE && app.bms.iden_fsm.status != IDENTIFY_END_STATE) || \
            (app.bms.config_fsm.status != CONFIG_IDLE_STATE && app.bms.config_fsm.status != CONFIG_END_STATE) || \
            (app.bms.charg_fsm.status != CHARGING_IDLE_STATE && app.bms.charg_fsm.status != CHARGING_END_STATE) || \
            (app.status == CHARGE_END_STATE) || (app.status == CHARGE_INSU_STATE))
        {
            if (app.bms.app_q != NULL && app.pwr.power_q != NULL)
            {
                bms_q_ret = xQueueReceive(app.bms.app_q, (qmsg_t *)&qmsg, 5u);
                app.bms.msg = &qmsg;
                pwr_q_ret = xQueueReceive(app.pwr.power_q, (pwr_msg_t *)&pmsg, 5u);
                app.pwr.msg = &pmsg;
            }
            else
            {
                log_e("p == NULL.");
                configASSERT(app.bms.app_q);
                configASSERT(app.pwr.power_q);
            }
        }

        if (pwr_q_ret != pdFALSE) {
            pwr_fault(&app);
            charge_err(&app);
        }

        if (bms_q_ret != pdFALSE) {
            bms_fault(&app);
            bms_error(&app);
        }
        charge_fault(&app);
        emergency_ctrl_fsm(&app);
        charge_fsm(&app);
        /* 清空缓存的数据，防止死循环 */
        memset((uint8_t *)&app.bms.msg->j1939_bms, 0, sizeof(j1939_msg_info_t));
        memset((uint8_t *)app.pwr.msg, 0, sizeof(pwr_msg_t));
        osDelay(1u);
    }
}

/**
 * @brief Get the bms struct object
 * @return bms_t* BMS的结构
 */
bms_t *get_bms_struct(void) {
    return &app.bms;
}

/**
 * @brief Get the pwr struct object
 * @return pwr_t*  PWR的结构
 */
pwr_t *get_pwr_struct(void) {
    return &app.pwr;
}
